#include "CompresorDePunteros.h"
#include <iostream>

CompresorDePunteros::CompresorDePunteros() {
	this->buffer = new char[SIZE_PUNTEROS];
	memset(buffer,0,SIZE_PUNTEROS);
	this->pos_actual = 0;
	this->offset_en_bits = 0;
	this->pos_actual_bits = 0;
	this->salida = 0;
	this->pos_actual_offset = 0;
}

CompresorDePunteros::~CompresorDePunteros() {
	delete[] this->buffer;
}

void CompresorDePunteros::comprimir(Doc_frec* par[], int cantidad) {
	std::string a_grabar;
	Delta delta;
	int j = 0;

	while( j  < cantidad) {
		std::string aux1= delta.comprimir(par[j]->doc);
		std::string aux2 = delta.comprimir(par[j]->frec);
		a_grabar += aux1;
		a_grabar += aux2;
		j++;
	}


	int i = 0;
	unsigned char aux = this->buffer[pos_actual_offset];
	bool fin = false;
	unsigned char uno = 128;
	unsigned char cero = 0;
	int cant_a_eliminar = 0;

	while (!fin) {
		int tamanio_string = a_grabar.size();
		i = 0;
		if (tamanio_string > 8) {
			//i = 7;
			cant_a_eliminar = 8;
		}
		else {
			//i = tamanio_string -1;
			cant_a_eliminar = tamanio_string;
		}
		while (i < cant_a_eliminar) {
			if (a_grabar[i] == '1') {
				aux = aux | uno;
			}
			else {
				aux = aux | cero;
			}
			this->pos_actual_bits = this->pos_actual_bits +1 ;
			this->offset_en_bits = this->offset_en_bits + 1;
			i++;
			if (offset_en_bits == 8) {
				this->buffer[this->pos_actual_offset] = aux;
				this->pos_actual++;
				this->pos_actual_offset++;
				if (this->pos_actual > SIZE_PUNTEROS) {
					fwrite(buffer, SIZE_PUNTEROS, sizeof(char),salida);
					memset(buffer, 0, SIZE_PUNTEROS);
					pos_actual_offset = 0;
				}
				offset_en_bits = 0;
				aux = 0;
			}
			else {
				aux = aux >> 1;
			}

			if (( i == cant_a_eliminar ) && (offset_en_bits != 0)) {
				this->buffer[this->pos_actual_offset] = aux;
			}
		}
		a_grabar.erase(0,cant_a_eliminar);
		if  (a_grabar.size() == 0) {
			fin = true;
		}
	}
}

std::string CompresorDePunteros::descomprimir(int bit_d, int bit_h,  const std::string &path) {
	std::string cadena;
	int byte_comienzo = bit_d / 8;
	int resto_comienzo = bit_d % 8;
	int byte_fin = bit_h / 8;
	int offset = (byte_fin -byte_comienzo) + 1;
	char* buff = new char[offset];
	FILE* punteros = fopen(path.c_str(), "r");
	fseek(punteros,byte_comienzo,SEEK_SET);
	fread(buff,offset,sizeof(char),punteros);
	fclose(punteros);

	bool fin = false;
	int byte_actual = 0;
	char aux = buff[byte_actual];
	char uno = 1;
	char mascara = 0;
	int pos_actual_bits = bit_d;
	aux = aux >> resto_comienzo;
	int pos_bits = resto_comienzo;

	while (!fin) {


		mascara = aux & uno;
		if (mascara == uno) {
			cadena.push_back('1');
		}
		else {
			cadena.push_back('0');
		}
		pos_actual_bits++;
		pos_bits++;

		if (pos_actual_bits > bit_h) {
			fin = true;
		}
		if (pos_bits == 8) {
			if (!fin) {
				byte_actual++;
				aux = buff[byte_actual];
				pos_bits = 0;
			}
		}
		else {
			aux = aux >> 1;
		}

	}
	delete[] buff;
	return cadena;
}

int CompresorDePunteros::getPosActual() {
	return this->pos_actual_bits;
}


void CompresorDePunteros::setPath(const std::string &path) {
	this->path = path;
	this->salida = fopen(path.c_str(),"w+");
}

void CompresorDePunteros::grabarBufferActual() {
	int size_en_bytes = this->pos_actual_offset;
	if ((this->offset_en_bits) != 0 ){
		size_en_bytes++;
	}
	fwrite(this->buffer,size_en_bytes,sizeof(char),salida);
}

void CompresorDePunteros::cerrar() {
	fclose(this->salida);
}
